home *** CD-ROM | disk | FTP | other *** search
- /*
- This a called 'Make' and is a much simplified version of
- the make utility on UNIX (a trademark or something of AT&T)
- written using the Lattice C compile
- for the IBM Personal Computer. The Lattice package is
- available from Lifeboat Assoc. 1651 Third Avenue
- New York, NY 10128 .
-
- 'Make' takes a file of dependencies (a 'makefile') and
- decides what commands have to be executed to bring the files
- up to date. These commands are either executed directly from
- 'Make' or written to the standard output without executing
- them.
-
- 'Makefile' format:
- - There must be a 'makefile'; you can't take input from the
- standard input.
- - The default name of the 'makefile' is 'MAKEFILE' on the
- default disk. Different 'makefiles' can be specified using
- the '-f' option on the command line. If the '-f' option is
- used, the default 'makefile' is not processed.
- - Any blank lines in the 'makefile(s)' are ignored.
- - A line in a 'makefile' that starts with a tab character is
- a 'howto' line and consists of a command name followed by
- arguments. The command name must be a file name, e.g.
- 'cc'. When commands are executed, the PATH environment
- variable is used to find the command, in (hopefully) the
- same manner as DOS does. 'Howto' lines apply to the most
- recently preceding 'dependency' line. It is an error for
- a 'howto' line to precede the first 'dependency' line.
- - Any other non-blank line is a 'dependency' line. 'Dependency'
- lines consist of a filename followed by a (possibly empty) list
- of dependent filenames.
-
- Operation:
- Syntax:
- make [filename] [-f makefilename] [-i] [-n]
- -i means continue even if an error is encountered while
- executing a command.
- -n means don't execute the commands, just write the ones that
- should be executed to the standard output. This is useful
- for creating batch files, for example.
- -f specifies that the following argument is the name of a makefile
- to be used instead of the default (MAKEFILE).
- All arguments may be repeated and relative position of the
- arguments is not important. If multiple definitions of a file
- are found, only the first one is significant.
-
- First, 'Make' reads all of the makefiles. It then proceeds through
- all of the filename arguments, 'making' each one in turn. A file
- is remade if it is out of date with respect to the files it depends
- on or is non-existent. Dependencies are processed in a 'tree' fashion,
- so that the lowest-order files are remade first.
-
- 'Make' cannot execute DOS built-in commands e.g. 'cd' or 'dir'.
- 'Make' uses the first 20k or so after the resident portion of DOS.
- all definitions and howto's are stored in dynamically allocated struct's.
- Any executed commands are loaded above 'Make' in memory.
-
- 'Make' REQUIRES DOS 2.0 (or higher?).
-
-
- The code is a little kludgy in places.
-
- No guarantees or warranties of any kind: I think it works and
- I use it.
-
- Any suggestions for improvements gratefully accepted.
-
- I believe that commercial versions exist. I also beleive that they
- would be superior to this.
-
- version 2.0 comments:
- This program was converted to Lattice 'C' ver 2.11 on 15 jun 84.
- This allowed the use of the lattice 'fork' command. The command
- will automatically search the path name specified to find the
- desired executable image. This also allows the use of image names
- with out the extension. ie 'lc1' instead of 'lc1.exe'. All of
- the assembler routines have been replaced with lattice dos calls.
-
- The Lattice version uses about 55k bytes less memory than the
- Desmet version. This is nice for the systems with already tight
- memory requirements.
- version 3 comments:
- The default makefile name is MAKEFILE not MAKEFILE.DAT.
- There now is a symbol processor to do substitiutions
- in the argument line.
- A symbol definition MUST begin with a $.
- An example follows.
- Fixed a bug-If a dependent file did not exist then make didn't
- work correctly.
- Checks to see if a command results in a non-zero return code.
- If so then aborts unless the -i flag is used.
-
- Any comments on this code should be directed to
- Jeffrey Spidle
- Systems Analyst
- Office of Continuing Education
- Iowa State University
- Ames, IA 50011
- or a message on one of the following BBS.
- Gene Plantz (312)887-4227
- Lynn Long (918)749-0718
- Bob Blackwell (319)363-3314
-
-
- */
-
-
- /*
- Written by John M Sellens, April, 1984
- Modified for Lattice C ver 2.11 by Jeff Spidle jun 15 84
-
- Code is all original except where indicated otherwise.
-
- Until August, 1984:
- jmsellens@watrose.UUCP
-
- 107 - 180 Brybeck Cres.
- Kitchener, Ontario
- N2M 5G4
-
- After August, 1984:
- c/o 1135 Lansdowne Ave. SW
- Calgary, Alberta
- T2S 1A4
-
- (c) Copyright 1984 John M Sellens
- Permission is granted to use, distribute and/or modify this code unless
- done for direct commercial profit. If you find these routines useful,
- modest contributions (monetary or otherwise) will be gratefully accepted.
- Author's name, address and this notice must be included in any copies.
-
- <TAB> = ASCII 09
- An example: To compile this program the following makefile was used
- $CFLAGS -ms -i/code/c/lc/
- make.exe make.obj
- <TAB>link /code/c/lc/s/cs+make,make,make,/code/c/lc/s/lcs -map
- make.obj make.c /code/c/lc/stdio.h
- <TAB>lc1 make $CFLAGS -i/code/c/lc/s/ -n
- <TAB>lc2 make
-
- An explination: make.exe is a dependent file. Is is dependent on
- make.obj. make.obj is dependent on make.c and stdio.h. If the
- following command is issued:MAKE make.exe then make will
- check to see if either make.c or stdio.h has a newer date&time
- than make.obj. if so then the 2 compile instructions are issued.
- then the link instruction will be issued. If only make.obj is
- newer than make.exe then only the link step would be executed.
-
- The symbol substitution will end up having the lc1 call look like
- lc1 make -ms -i/code/c/lc/ -i/code/c/lc/s/ -n
-
- Hints: Dependencies can be in any order. Make will resolve them
- correctly.
-
- How to lines must begin with a <TAB> not just 7 spaces.
-
- Symbol definition lines must start with a $.
-
- Symbols cannot have other symbols in their definition.
-
- A symbol may have a max of 39 characters.
-
- The equate for a symbol may be up to 80 characters.
-
- You may have an unlimited(within reason) number of
- symbols.
-
- A symbol that is not defined will be copied to the
- output line. ie
- lc2 $TEST
- with $TEST not defined will create the command
- lc2 $TEST
-
- Symbols are case specific. upper and lower case are significant.
-
- The command line must specify what file you wish to
- make. You may have more than one set of file definitions
- in a makefile. If you do you may run out of memory. I
- haven't run into this yet but I suppose it is possible.
-
- If a command returns an error-code (ERRORLEVEL) not equal
- to zero then MAKE thinks that there was an error. MAKE
- will abort processing unless the -i (ignore errors) flag
- is used.
-
- Any suggestions or improvements will be much appreciated. I
- am next going to try to put definable symbols for substitution
- in a makefile next aka UNIX-MAKE. So we will see what happens.
- */
-
-
- #include <stdio.h>
- #include <dos.h>
- #include <ctype.h>
-
- #define TRUE 1
- #define FALSE 0
- #define DEFAULT "MAKEFILE"
- #define INMAX 255 /* maximum input line length */
- extern char *getmem() ;
- extern int _oserr, errno ;
-
-
- struct sym_ptr
- {
- struct sym_str *data ;
- struct sym_ptr *next ;
- } ;
-
- struct sym_str
- {
- char symbol[40] ; /* max symbol size in lattice c is 39 chars */
- char equals[81] ; /* so we had to default to something */
- } ;
-
- /* declare some global variables for the symbols */
- struct sym_ptr list ;
- struct sym_ptr *current ; /* pointer to the current symbol */
- /* thus we know where to add more to */
-
- struct howrec {
- char *howcom,*howargs;
- struct howrec *nexthow;
- };
-
- struct deprec {
- char *name;
- struct defnrec *def;
- struct deprec *nextdep;
- };
-
- struct defnrec {
- char *name;
- int uptodate;
- long modified;
- struct deprec *dependson;
- struct howrec *howto;
- struct defnrec *nextdefn;
- };
-
- struct dorec {
- char *name;
- struct dorec *nextdo;
- };
-
- struct defnrec *defnlist;
- struct dorec *dolist;
-
- int execute;
- int stopOnErr;
- int madesomething;
- int knowhow;
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
- long make();
- long void ;
- current = &list ;
- current->next = NULL ;
- current->data = NULL ;
- init(argc,argv);
-
- /* now fall down the dolist and do them all */
- while (dolist != NULL) {
- madesomething = FALSE;
- void = make(dolist->name); /* ignore return value */
- if (!madesomething) {
- if (knowhow)
- fprintf(stderr,"Make: '%s' is up to date\n",dolist->name);
- else {
- fprintf(stderr,"Make: Don't know how to make '%s'\n",
- dolist->name);
- if (stopOnErr)
- exit(-1);
- }
- }
- dolist = dolist->nextdo;
- }
- }
-
- init(argc,argv)
- int argc;
- char *argv[];
- {
- int i, usedefault;
- dolist = NULL;
- defnlist = NULL;
- usedefault = TRUE;
- execute = TRUE;
- stopOnErr = TRUE;
-
- for (i=1; i < argc; i++) {
- if (argv[i][0] == '-') { /* option */
- switch (argv[i][1]) {
- case 'f': case 'F': /* arg following is a makefile */
- if (++i < argc) {
- readmakefile(argv[i]);
- usedefault = FALSE;
- } else {
- fprintf(stderr,"Make: '-f' requires filename\n");
- exit(-1);
- }
- break;
- case 'i': case 'I': /* ignore errors on execution */
- stopOnErr = FALSE;
- break;
- case 'n': case 'N': /* don't execute commands - just print */
- execute = FALSE;
- break;
- default:
- fprintf(stderr,"Make: unknown option '%s'\n",argv[i]);
- }
- } else { /* it must be something to make */
- add_do(argv[i]);
- }
- }
- if (usedefault)
- readmakefile(DEFAULT);
-
- }
-
- long make(s) /* returns the modified date/time */
- char *s;
- {
- struct defnrec *defnp;
- struct deprec *depp;
- struct howrec *howp;
- char exp_args[128] ;
- char system_call[255] ;
- long latest, getmodified(), lmax(), currtime();
- int void, return_code ;
-
- /* look for the definition */
- defnp = defnlist;
- while (defnp != NULL) {
- if (strcmp(defnp->name,s) == 0)
- break;
- defnp = defnp->nextdefn;
- }
-
- if (defnp == NULL) { /* don't know how to make it */
- knowhow = FALSE;
- latest = getmodified(s);
- if (latest==0) { /* doesn't exist but don't know how to make */
- fprintf(stderr,"Make: Can't make '%s'\n",s);
- exit(-1);
- } else /* exists - assume it's up to date since we don't know */
- return(latest);
- }
-
- if (defnp->uptodate)
- return(defnp->modified);
-
- /* now make sure everything that it depends on is up to date */
- latest = 0;
- depp = defnp->dependson;
- while (depp != NULL) {
- latest = lmax(make(depp->name),latest);
- depp = depp->nextdep;
- }
-
- knowhow = TRUE; /* has dependencies therefore we know how */
-
- /* if necessary, execute all of the commands to make it */
- /* if (out of date) || (depends on nothing) */
- if (latest > defnp->modified || defnp->dependson==NULL) {
- /* make those suckers */
- howp = defnp->howto;
- while (howp != NULL) {
- expand_args(howp->howargs, exp_args) ;
- printf("%s %s\n",howp->howcom,exp_args);
- if (execute)
- {
- void = forklp(howp->howcom,exp_args,NULL) ;
- if (void == 0) /* success loading function */
- {
- /* now do a wait to see if the function returns an ok code */
- return_code = wait() ;
- if (return_code != 0) /* error code returned */
- {
- printf("MAKE: error returned from %s %s, code = %d\n",
- howp->howcom, exp_args, return_code ) ;
- if (stopOnErr)
- exit(-1);
- } /* endif return_code != 0 */
- }
- else
- { /* fork had an error loading */
- if (_oserr == 2) /* error for file not found */
- { /* lets do a system call instead then */
- strcpy( system_call, howp->howcom ) ;
- strcat( system_call, " " ) ;
- strcat( system_call, exp_args ) ;
- void = system( system_call ) ;
- if (void != 0) /* error in system call */
- {
- printf("MAKE: system call error from %s %s, code = %d\n",
- howp->howcom, exp_args, _oserr ) ;
- if (stopOnErr)
- exit(-1);
- } /* endif id void != 0 */
- }
- else
- {
- printf("\nMake: error on '%s %s' _oserr = %d\n",
- howp->howcom,exp_args, _oserr);
- if (stopOnErr)
- exit(-1);
- } /* endif _oserr == 2 */
- } /* endif void == 0 */
- } /* endif execute */
- howp = howp->nexthow;
- } /* end while */
- defnp->modified = currtime();
- defnp->uptodate = TRUE;
- if (defnp->howto != NULL) /* we had instructions */
- madesomething = TRUE;
- }
-
- return(defnp->modified);
-
- }
-
- expand_args( in, out )
- char *in, *out ;
- {
- char *posin, *posout, *possym ;
- char symbol[40] ;
- char *get_symval(), *symval ;
-
- posin = in ;
- posout = out ;
- while (TRUE)
- {
- while ( (*posin != '$') && (*posin != '\0') )
- *posout++ = *posin++ ; /* copy till we find a $ */
-
- if (*posin == '\0') /* have reached the end of the input */
- { /* so exit */
- *posout = '\0' ; /* terminate the output string first tho */
- return ;
- }
-
- possym = symbol ; /* point symbol pointer at the begining */
- /* skip over the $ so we can test for alphanumeric */
- *possym++ = *posin++ ; /* copy's the $ */
- while ( isalnum(*posin) )
- *possym++ = *posin++ ; /* copy in the suspected symbol */
- *possym = '\0' ; /* zero terminate it */
- /* get the value of the found symbol */
- if ( (symval = get_symval( symbol )) == NULL )
- { /* do this if there isn't a symbol match */
- possym = symbol ; /* reset the symbol position */
- /* copy the symbol to the output */
- while (*possym != '\0' )
- *posout++ = *possym++ ;
- }
- else /* do this if there is one */
- {
- /* copy the symbol equate to the output */
- while (*symval != 0)
- *posout++ = *symval++ ;
- }
- }
- /* should never get to here */
- return ;
- }
-
- char *get_symval( symbol )
- char *symbol;
- {
- struct sym_ptr *cur_ptr ;
-
- cur_ptr = &list ; /* start at the begining of the list */
- while (cur_ptr->data != NULL) /* while there is data */
- {
- if (strcmp(cur_ptr->data->symbol, symbol) == 0) /* they match */
- {
- return(cur_ptr->data->equals) ; /* return the pointer to */
- /* the equate string */
- }
- else /* they dont */
- cur_ptr = cur_ptr->next ; /* point cur_ptr to the next symbol */
- }
- return(NULL) ;
- }
-
- add_do(s)
- char *s;
- {
- struct dorec *ptr1, *ptr2;
- char *get_mem();
-
- ptr1 = (struct dorec *)get_mem(sizeof(struct dorec));
-
- ptr1->name = s; /* okay since only called with an argv */
- ptr1->nextdo = NULL;
-
- uppercase(ptr1->name);
-
- /* now go down the dolist */
- if (dolist == NULL)
- dolist = ptr1;
- else {
- ptr2 = dolist;
- while (ptr2->nextdo != NULL)
- ptr2 = ptr2->nextdo;
- ptr2->nextdo = ptr1;
- }
-
- }
-
-
- readmakefile(s)
- char *s;
- {
- int doneline, pos, i, j;
- long getmodified() ;
- FILE *fil ;
- char inline[INMAX], info[INMAX];
- char *get_mem();
- struct defnrec *defnp, *defnp2;
- struct deprec *depp, *depp2;
- struct howrec *howp, *howp2;
-
- if ( (fil = fopen(s,"r")) == NULL)
- {
- fprintf(stderr,"Make: Couldn't open '%s'\n",s);
- return;
- }
-
- while (fgets(inline,INMAX,fil) != NULL)
- {
- inline[strlen(inline)-1] = '\0'; /* strip trailing newline */
-
- if (inline[0] == '\0') /* ignore blank lines */
- continue;
-
- switch (inline[0])
- {
- default:
- uppercase(inline);
-
- /* get what we're defining into info */
- if (sscanf(inline,"%s ",info) != 1)
- {
- fprintf(stderr,"Make: Can't scan: '%s'\n",inline);
- continue;
- }
- /* get a new struct */
- defnp = (struct defnrec *)get_mem(sizeof(struct defnrec));
- /* add it to the end of defnlist */
- if (defnlist == NULL)
- defnlist = defnp;
- else
- {
- defnp2 = defnlist;
- while (defnp2->nextdefn != NULL)
- defnp2 = defnp2->nextdefn;
- defnp2->nextdefn = defnp;
- }
- /* initialize it */
- defnp->name = get_mem(strlen(info)+1);
- strcpy(defnp->name,info);
- defnp->uptodate = FALSE; /* actually unknown */
- defnp->modified = getmodified(defnp->name);
- defnp->dependson = NULL;
- defnp->howto = NULL;
- defnp->nextdefn = NULL;
-
- /* now go through all of its dependecies */
- /* first move past the first name */
- pos = 0;
- while (isspace(inline[pos]))
- pos++;
- while (!isspace(inline[pos]) && inline[pos]!='\0')
- pos++;
- /* now loop through those suckers */
- doneline = FALSE;
- while (!doneline)
- {
- while (isspace(inline[pos]))
- pos++;
- if (inline[pos] == '\0')
- {
- doneline = TRUE;
- continue;
- }
- for(i = 0; !isspace(inline[pos]) && inline[pos]!='\0'; )
- info[i++] = inline[pos++];
- info[i] = '\0';
- /* get a new struct */
- depp = (struct deprec *)get_mem(sizeof(struct deprec));
- /* add it to the end of deplist */
- if (defnp->dependson == NULL)
- defnp->dependson = depp;
- else
- {
- depp2 = defnp->dependson;
- while (depp2->nextdep != NULL)
- depp2 = depp2->nextdep;
- depp2->nextdep = depp;
- }
- depp->name = get_mem(strlen(info)+1);
- strcpy(depp->name,info);
- depp->nextdep = NULL;
- }
- break ;
- case '+': /* must be a continuation line */
- uppercase(inline);
-
- /* now go through all of its dependecies */
- /* first move past the + sign */
- pos = 1;
- /* now loop through those suckers */
- doneline = FALSE;
- while (!doneline)
- {
- while (isspace(inline[pos]))
- pos++;
- if (inline[pos] == '\0')
- {
- doneline = TRUE;
- continue;
- }
- for(i = 0; !isspace(inline[pos]) && inline[pos]!='\0'; )
- info[i++] = inline[pos++];
- info[i] = '\0';
- /* get a new struct */
- depp = (struct deprec *)get_mem(sizeof(struct deprec));
- /* add it to the end of deplist */
- if (defnp->dependson == NULL)
- defnp->dependson = depp;
- else
- {
- depp2 = defnp->dependson;
- while (depp2->nextdep != NULL)
- depp2 = depp2->nextdep;
- depp2->nextdep = depp;
- }
- depp->name = get_mem(strlen(info)+1);
- strcpy(depp->name,info);
- depp->nextdep = NULL;
- }
- break ;
- case '$': /* must be a symbol definition */
- /* now split the line up into symbol and args */
- for (pos=0;isspace(inline[pos]); pos++);
- ;
- for (i=pos; !isspace(inline[i]) && inline[i]!='\0'; i++)
- ;
- /* if there is something there, allocate mem and copy */
- if (i != pos)
- {
- /* get a new struct */
- current->data = (struct sym_str *)get_mem(sizeof(struct sym_str));
- current->next = (struct sym_ptr *)get_mem(sizeof(struct sym_ptr));
- for(j=0; pos < i; )
- current->data->symbol[j++] = inline[pos++] ;
- current->data->symbol[j] = '\0';
- /* now look for any argumentative part */
- while (isspace(inline[pos]))
- pos++;
- for(i=0; inline[pos] != '\0'; )
- current->data->equals[i++] = inline[pos++] ;
- current->data->equals[i] = '\0' ;
- current = current->next ;
- current->next = NULL ;
- current->data = NULL ;
- }
- break ;
- case '\t':
- if (defnp == NULL)
- {
- fprintf(stderr,"Make: Howto line without a definition\n");
- fprintf(stderr,"Make: '%s'\n",inline);
- }
- /* now split the line up into command and args */
- for (pos=0;isspace(inline[pos]); pos++);
- ;
- for (i=pos; !isspace(inline[i]) && inline[i]!='\0'; i++)
- ;
- /* if there is something there, allocate mem and copy */
- if (i != pos)
- {
- /* get a new struct */
- howp = (struct howrec *)get_mem(sizeof(struct howrec));
- /* add it to the end of howlist */
- if (defnp->howto == NULL)
- defnp->howto = howp;
- else
- {
- howp2 = defnp->howto;
- while (howp2->nexthow != NULL)
- howp2 = howp2->nexthow;
- howp2->nexthow = howp;
- }
- /* copy command filename */
- howp->howcom = get_mem(i-pos+1);
- for(j=0; pos < i; )
- howp->howcom[j++] = inline[pos++];
- howp->howcom[j] = '\0';
- /* now look for any argumentative part */
- while (isspace(inline[pos]))
- pos++;
- howp->howargs = get_mem(strlen(inline)-pos + 1);
- for(i=0; inline[pos] != '\0'; )
- howp->howargs[i++] = inline[pos++];
- howp->howargs[i] = '\0';
- howp->nexthow = NULL;
- } /* if */
- break ;
- } /* switch */
- } /* while */
- fclose( fil ) ;
- } /* readmakefile */
-
-
- uppercase(s)
- char *s;
- {
-
- for( ; *s != '\0'; s++)
- *s = toupper(*s);
- }
-
-
- char *get_mem(size) /* different name to differentiate it */
- int size; /* from lattice C 2.11 function */
- {
- char *p;
-
- if ((p = getmem(size)) == NULL) {
- fprintf(stderr,"Make: Ran out of memory...\n");
- exit(-1);
- }
- return(p);
- }
-
-
- long getmodified(name)
- char *name;
- {
- struct dt_tm {
- int time ;
- int date ;
- } ;
-
- union vals {
- long ret_dt ;
- struct dt_tm dt ;
- } out_val ;
-
- union REGS in_regs ;
- union REGS out_regs ;
-
- union FLAGS ret_flags ;
- int file_handle ;
-
- /* get the file handle */
- in_regs.x.dx = (int)name ;
- in_regs.h.al = 0 ;
- in_regs.h.ah = 0x3d ;
- ret_flags.all_flags = intdos( &in_regs, &out_regs ) ;
- file_handle = out_regs.x.ax ;
- /* if the file doesn't exist then return 0 for date&time */
- if ((ret_flags.flags.cf == 1) && ((file_handle == 2) ||
- (file_handle == 4) ||
- (file_handle == 5) ||
- (file_handle == 12)))
- {
- return( 0 ) ;
- }
-
- /* get the date */
- in_regs.x.bx = file_handle ;
- in_regs.h.al = 0 ;
- in_regs.h.ah = 0x57 ;
- intdos( &in_regs, &out_regs ) ;
- out_val.dt.date = out_regs.x.dx ;
- out_val.dt.time = out_regs.x.cx ;
-
- /* close out the file */
- in_regs.x.bx = file_handle ;
- in_regs.h.ah = 0x3e ;
- intdos( &in_regs, &out_regs ) ;
- return( out_val.ret_dt ) ;
-
- }
-
- long currtime()
- /* return a long encoding the current date and time */
- {
- union {
- long ret_dt ;
- int dt[2] ;
- } out_val ;
-
- union REGS in_regs ;
- union REGS out_regs ;
-
- in_regs.h.al = 0 ;
- in_regs.h.ah = 0x2a ;
- intdos( &in_regs, &out_regs ) ;
- out_regs.x.cx -= 1980 ;
-
- out_val.dt[1] = (out_regs.x.cx << 9) ;
- out_val.dt[1] |= (out_regs.h.dh << 5) ;
- out_val.dt[1] |= (out_regs.h.dl ) ;
-
- in_regs.h.al = 0 ;
- in_regs.h.ah = 0x2c ;
- intdos( &in_regs, &out_regs ) ;
- out_val.dt[0] = (out_regs.h.ch << 11) ;
- out_val.dt[0] |= (out_regs.h.cl << 5) ;
- out_val.dt[0] |= (out_regs.h.dh >> 1) ;
- return( out_val.ret_dt ) ;
-
- }
-
- long lmax(a,b)
- long a,b;
- {
- return(a>b ? a : b);
- }
- /* ---------- */